package sia.tpIntro;


public class Genotype extends AbstractGenotype<Double> {
	
	static Integer precision;
	
	private double fenotype;
	private String chromosome;
	
	public Genotype(Double fenotype) throws Exception {
		if (precision == null) {
			throw new Exception("Precision not set");
		}
		
		if (fenotype > Math.pow(2, precision) - 1) {
			throw new Exception("Precision overflow");
		}
		
		this.fenotype = fenotype;
		this.chromosome = fenotypeToChromosome(fenotype);
	}

	/*
	 * Interface Implementation
	 */
	
	@Override
	public String fenotypeToChromosome(Double fenotype) {
		String fenotypeAsChromosome = Long.toBinaryString(Double.doubleToLongBits(fenotype));
		String fenotypeAsChromosomeComplete = new String();
		
		for( int i=0 ; i<precision-fenotypeAsChromosome.length() ; i++)
			fenotypeAsChromosomeComplete = fenotypeAsChromosomeComplete.concat("0");
			
		return fenotypeAsChromosomeComplete.concat(fenotypeAsChromosome); 
	}

	@Override
	public Double chromosomeToFenotype(String chromosome) {
		return Double.longBitsToDouble(Long.parseLong(chromosome, 2));
	}
	
	@Override
	public String toString() {
		return String.valueOf(fenotype);
	}

	@Override
	public AbstractGenotype<Double> cross(AbstractGenotype<Double> genotype,int crossPoint) {
		Genotype crossover = null;
		Genotype gen = (Genotype) genotype;
		
		try {
			crossover = new Genotype(0.0);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		//Hago el cruce en string
		try {
		crossover.chromosome = chromosome.substring(0, crossPoint+1).concat(gen.chromosome.substring(crossPoint+1, gen.chromosome.length()));	
		} catch (Exception e) {
			System.out.println("Error en el cruce!");
		}
		//Seteo el integer segun el numero que me dio en string binario
		crossover.fenotype = chromosomeToFenotype(crossover.chromosome);
		crossover.chromosome = fenotypeToChromosome(crossover.fenotype);
		
		return crossover;
	}

	@Override
	public void mutate(double mutationP) {
		char[] chromosomeArray = chromosome.toCharArray();
		
		for(int i=0 ; i<chromosome.length() ; i++) {
			if( Math.random() <= mutationP )
				chromosomeArray[i] = (chromosomeArray[i]=='0'?'1':'0');
		}
		chromosome = String.copyValueOf(chromosomeArray);
		
		//normalize
		fenotype = chromosomeToFenotype(chromosome);
		chromosome = fenotypeToChromosome(fenotype);
		
	}
	
	
	/*
	 * Getters and Setters
	 */
	public String getChromosome() {
		return chromosome;
	}

	public void setAptitude(double aptitude) {
		this.aptitude = aptitude;
	}

	public void setAcumAptitude(double aptitude) {
		this.acumAptitude = aptitude;
	}
	
	public static Integer getPrecision() {
		return precision;
	}

	public static void setPrecision(Integer precision) throws Exception {
		if (precision < 0) {
			throw new Exception("Precision cannot be negative");
		}
		
		Genotype.precision = precision;
	}

	public String getFenotypeAsString() {
		return chromosome;
	}

	public Double getFenotype() {
		return fenotype;
	}
}
